T002 自定义控件 裁剪圆形和圆角头像

参考知识点:01.5 精通自定义 View 之绘图基础——Canvas

一、原理

利用 clip 系列函数,通过与 Rect、Path、Region 取交、并、差等集合运算来获得最新的画布形状。此处只需要裁处圆形和圆角矩形,使用 Path 类构建即可,并用 clipPath 裁剪画布。

1
2
3
4
5
6
7
Path path = new Path();
RectF rect = new RectF(50, 50, 240, 200);
path.addRoundRect(rect, 10, 10, Path.Direction.CCW);
// float[] radii = {10,15,20,25,30,35,40,45};
// path.addRoundRect(rect, radii, Path.Direction.CW);
canvas.clipPath(path);

二、步骤

1. 初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class RoundImageView extends View {
private Paint mPaint;
private Path mPath;
private Bitmap mBmp;
public RoundImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 禁用硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
mPaint = new Paint();
mPath = new Path();
mBmp = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);
int x = mBmp.getWidth() / 2;
int y = mBmp.getHeight() / 2;
int r = Math.min(x, y);
mPath.addCircle(x, y, r, Path.Direction.CCW);
}
}

在使用 clip 系列函数时,要禁用硬件加速功能。然后利用 BitmapFactory.decodeResource() 函数从本地 res 文件夹中提取一个 Bitmap 文件。接着根据位图文件的大小,构造一条与图像大小相同的圆形路径。

2. 绘制圆形图像

在绘图时,先将画布裁剪成圆形,再将位图画上去。

1
2
3
4
5
6
7
8
9
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.clipPath(mPath);
canvas.drawBitmap(mBmp, 0, 0, mPaint);
canvas.restore();
}

效果图

4. 绘制圆角图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class RoundImageView extends View {
private Paint mPaint;
private Path mPath;
private Bitmap mBmp;
private boolean isCircle = false; // true:圆形图像;false:圆角矩形
public RoundImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 禁用硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
mPaint = new Paint();
mPath = new Path();
mBmp = BitmapFactory.decodeResource(getResources(), R.drawable.head);
if (isCircle) {
int x = mBmp.getWidth() / 2;
int y = mBmp.getHeight() / 2;
int r = Math.min(x, y);
mPath.addCircle(x, y, r, Path.Direction.CCW);
} else {
RectF rectF = new RectF();
rectF.set(0, 0, mBmp.getWidth(), mBmp.getHeight());
mPath.addRoundRect(rectF, 20, 20, Path.Direction.CW);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.clipPath(mPath);
canvas.drawBitmap(mBmp, 0, 0, mPaint);
canvas.restore();
}
}

圆角图像

三、优化

对上述代码可以进行以下几个方面优化:

  • 参数可配置:圆形与圆角矩形切换、圆角大小、图片资源等。
  • 图片缩放至控件大小。

由于 Android 提供的 ImageView 已经处理好了各种缩放问题,我们可以在它的基础上添加一个显示圆角圆形的功能。详见博客:圆角圆形ImageView。